#include "topdbs_base_session.hpp"

namespace topdbs
{
	topdbs_base_session::topdbs_base_session()
		: m_isResultSet(false)
		, m_data_index(0)
		, m_sqlrows(0)
		, m_isExecuted(false)
		, m_isPrepared(false)
		, m_commandType(DBS_CmdUnknown)
		, m_numParams(0)
	{
	};

	topdbs_base_session::~topdbs_base_session()
	{
	};

	void topdbs_base_session::setCommandText(const string& sSQL,eDBSCommandType_t commandType)
	{
		m_commandText = sSQL;
		m_commandType = commandType;
	};

	string& topdbs_base_session::getCommandText()
	{
		return m_commandText;
	};

	eDBSCommandType_t topdbs_base_session::CommandType() const
	{
		return m_commandType;
	}

	stringmap_row_t& topdbs_base_session::getRow()
	{
		return m_row;
	}

	stringmap_rs_t&  topdbs_base_session::getResult()
	{
		return m_res;
	}

	//! Tests whether a result set exists after the command execution.
	bool topdbs_base_session::isResultSet() const
	{
		return m_isResultSet;
	};

	//! Returns number of rows affected by last DML operation.
	long topdbs_base_session::RowsAffected() const 
	{
		return m_sqlrows;
	};

	//! Fetches next row from a result set.
	bool topdbs_base_session::FetchNext()    	
	{
		int isFoundNext = false;
		try
		{
			if(	m_res.size() == 0 || m_data_index+1 > m_res.size())
			{
				return isFoundNext;
			}
			stringmap_row_t().swap(m_row);
			m_row = m_res.at(m_data_index);
			isFoundNext = true;
		}
		catch(const std::exception &e)
		{
			return isFoundNext;
		}
		m_data_index++;
		return isFoundNext;
	}

	int topdbs_base_session::GetField(const std::string& iField,std::string& oValue)
	{
		string colname(iField);
		auto iter = m_row.find(topdbs_string::to_lower(colname));
		if(iter == m_row.end()) return ERR_DBS_NOTFOUND;
		oValue = iter->second;
		return ERR_DBS_OK;		
	};

	int topdbs_base_session::GetField(const std::string& iField,char* oValue)
	{
		string colname(iField);
		auto iter = m_row.find(topdbs_string::to_lower(colname));
		if(iter == m_row.end()) return ERR_DBS_NOTFOUND;
		strcpy(oValue,iter->second.c_str());
		return ERR_DBS_OK;		
	};

	int topdbs_base_session::GetField(const std::string& iField,int&  oValue)
	{
		std::string value;
		if(GetField(iField,value) != ERR_DBS_OK) return ERR_DBS_UNKOWN;
		oValue = topdbs_string::to_int<std::string>(value);
		return ERR_DBS_OK;		
	};

	int topdbs_base_session::GetField(const std::string& iField,long& oValue)
	{
		std::string value;
		if(GetField(iField,value) != ERR_DBS_OK) return ERR_DBS_UNKOWN;
		oValue = topdbs_string::to_long<std::string>(value);
		return ERR_DBS_OK;		
	};

	void topdbs_base_session::Reset()
	{
		m_row.clear();
		m_res.clear();
		m_sqlrows = 0;
		m_data_index = 0;
		m_isResultSet = false;
		m_commandType = eDBSCommandType::DBS_CmdUnknown;
		m_commandText.clear();
		m_isExecuted = false;
		m_isPrepared = false;
		m_commandFields.clear();
		m_numParams = 0;
	}

	int  topdbs_base_session::ExecuteV(const string& sSQL,va_list vaList)
	{ 
		m_commandText = sSQL;
		int colnum_count = cvtGetPreParamCount(m_commandText);
		int paranums = colnum_count;
		for(int column_col=0;column_col<paranums;column_col++)
		{
			char* pArgVar = va_arg(vaList,char* );
			if(pArgVar == NULL) 
			{
				break;
			}
			if( ReplaceParams(column_col,DBSValue().setAsString(pArgVar)) != ERR_DBS_OK)
			{
				return ERR_DBS_FAIL;
			}
		}	
		return ERR_DBS_OK; 
	}

	int topdbs_base_session::ReplaceParams(int paramno,const DBSValue& value)
	{
		if(!SQLBindCheck(value.toString()))
		{
			topdbs_string::format(m_sqlerr,"bind params error:check bind param %d value %s invalid",
				paramno,value.toString().c_str());
			dbslog(DBS_ERROR,"ReplaceParams Exception  [%s]",m_sqlerr.c_str());				
			return ERR_DBS_FAIL;
		}

		if( m_commandFields.size() > 0 )
		{
			cvtBindParams(m_commandText,m_commandFields,paramno,value.toString());
		}
		else 
		{	
			vector<string> v = cvtPrepareParams(m_commandText);
			cvtBindParams(m_commandText,v,0,value.toString());
			cvtFormatParams(m_commandText,v);		
		}
		dbslog(DBS_DEBUG,"ReplaceParams %d output=[%s]",paramno,m_commandText.c_str());
		return ERR_DBS_OK;
	}
}
